/**
 * @file Saliency.cpp
 * @author enemy1205 (enemy1205@qq.com)
 * @brief 显著性检验类
 * @date 2021-09-02
 */
#include "Saliency.h"
/**
 * @brief 图像展示函数
 */
void Saliency_demo::show() {
    imshow("Original Image", src);
    imshow("Saliency Map", saliencyMap);
    imshow("Binary Map", binaryMap);
    waitKey(0);
    destroyAllWindows();
}

/**
 * @brief 构造函数初始化
 * @param path 视频路径
 */
Saliency_demo::Saliency_demo() {
    cout << "请输入测试方法" << endl;
    cout << "0:SPECTRAL_RESIDUAL" << endl;
    cout << "1:FineGrained" << endl;
    cout << "2:ObjectnessBING" << endl;
    cout << "3:BinWangApr2014" << endl;
    cin >> mode;
    cout<<"请输入测试素材路径"<<endl;
    cin>>this->video_path;
    src = imread(video_path);
}

/**
 * @brief 运行主程序
 * @note 根据输入模式不同调用不同方法
 */
void Saliency_demo::run() {
    switch (mode) {
        case 0: {
            this->SPECTRAL_RESIDUAL(src);
            break;
        }
        case 1: {
            this->FineGrained(src);
            break;
        }
        case 2: {
            this->ObjectnessBING(src);
            break;
        }
        case 3: {
            this->BinWangApr2014();
            break;
        }
        default:
            break;
    }
}

/**
 * @brief SPECTRAL_RESIDUAL方法
 * @param img 待处理图像
 */
void Saliency_demo::SPECTRAL_RESIDUAL(const Mat &img) {
    saliencyAlgorithm = saliency::StaticSaliencySpectralResidual::create();
    // 计算显著性
    bool success = saliencyAlgorithm->computeSaliency(img, saliencyMap);
    if (success) {
        saliency::StaticSaliencySpectralResidual spec;
        // 二值化图像
        spec.computeBinaryMap(saliencyMap, binaryMap);
//        // 转换格式才能保存图片
//        saliencyMap.convertTo(saliencyMap, CV_8UC3, 256);
        show();
    } else cout << "Invalid Picture" << endl;
}

/**
 * @brief FineGrained方法
 * @param img 待处理图像
 */
void Saliency_demo::FineGrained(const Mat &img) {
    saliencyAlgorithm = saliency::StaticSaliencyFineGrained::create();
    bool success = saliencyAlgorithm->computeSaliency(img, saliencyMap);
    if (success) {
        saliency::StaticSaliencySpectralResidual spec;
        spec.computeBinaryMap(saliencyMap, binaryMap);
//        saliencyMap.convertTo(saliencyMap, CV_8UC3, 256);
        show();
    } else cout << "Invalid Picture" << endl;
}

/**
 * @brief ObjectnessBING
 * @note 调用模型检测
 * @param img 待处理图像
 */
void Saliency_demo::ObjectnessBING(const Mat &img) {
    saliencyAlgorithm = ObjectnessBING::create();
    vector<Vec4i> saliencyMap;
// 提取模型文件参数
    saliencyAlgorithm.dynamicCast<cv::saliency::ObjectnessBING>()->setTrainingPath(training_path);
    // 将算法检测结果保存在Results文件夹内
    saliencyAlgorithm.dynamicCast<cv::saliency::ObjectnessBING>()->setBBResDir("Results");
// 计算显著性
    bool success = saliencyAlgorithm->computeSaliency(img, saliencyMap);
    if (success) {
        // saliencyMap获取检测到的目标个数
        int ndet = int(saliencyMap.size());
        std::cout << "Objectness done " << ndet << std::endl;
        // 目标按可能性从大到小排列，maxd为显示前5个目标，step设置颜色，jitter设置矩形框微调
        int maxd = 5, step = 255 / maxd, jitter = 9;
        Mat draw = img.clone();
        for (int i = 0; i < std::min(maxd, ndet); i++) {
            // 获得矩形框坐标点
            Vec4i bb = saliencyMap[i];
            // 设定颜色
            Scalar col = Scalar(((i * step) % 255), 50, 255 - ((i * step) % 255));
            // 矩形框微调
            Point off(theRNG().uniform(-jitter, jitter), theRNG().uniform(-jitter, jitter));
            // 画矩形
            rectangle(draw, Point(bb[0] + off.x, bb[1] + off.y), Point(bb[2] + off.x, bb[3] + off.y), col, 2);
            // 颜色标注
            rectangle(draw, Rect(20, 20 + i * 10, 10, 10), col, -1);
        }
        imshow("BING", draw);
        show();
    } else {
        std::cout << "No saliency founded " << std::endl;
    }
}

/**
 * @brief BinWangApr2014方法
 * @note 对视频进行多帧分析
 */
void Saliency_demo::BinWangApr2014() {
    VideoCapture VC(video_path);
    Mat img;
    VC.read(img);
    saliencyAlgorithm = MotionSaliencyBinWangApr2014::create();
    // 设置数据结构大小
    saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->setImagesize(img.cols, img.rows);
    // 初始化
    saliencyAlgorithm.dynamicCast<MotionSaliencyBinWangApr2014>()->init();
    while (true) {
        VC.read(img);
        cvtColor(img, img, COLOR_BGR2GRAY);
        // 计算
        saliencyAlgorithm->computeSaliency(img, saliencyMap);
        imshow("image", img);
        // 显示
        imshow("saliencyMap", saliencyMap * 255);
        int c = waitKey(25);
        if (c == 27) {
            break;
        }
    }
}